﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Audio;

namespace CorporationWars
{
    [Serializable]
    public class CyberSector
    {
        public string Name { get; set; }
        public List<Corporation> Corporations = new List<Corporation>();
        Random rnd = new Random(DateTime.Now.Millisecond);

        public float speedTranBase = .1f;
        public float speedRotBase = .01f;

        public float speedTran = .1f;
        public float speedRot = .01f;

        public bool RenderStatic = false;
        Color staticColor = new Color(1, 1, 1, .5f);

        public Corporation inSideCorp = null;

        Corporation hoverCorp = null;

        protected List<SectorExit> _Exits = new List<SectorExit>();
        protected List<string> exitNames = new List<string>();

        [NonSerialized]
        public Game1 Game;

        public List<string> Exits
        {
            get { return exitNames; }
            set
            {
                exitNames = value;

                _Exits.Clear();
                int e = 0;
                Vector3 pos = Vector3.Zero;
                                          
                foreach (string exitName in Exits)
                {
                    switch (e)
                    {
                        case 0:
                            pos = new Vector3(Corporation.SpaceSize, Corporation.SpaceSize / 2, -Corporation.SpaceSize);
                            break;
                        case 1:
                            pos = new Vector3(-Corporation.SpaceSize, Corporation.SpaceSize / 2, -Corporation.SpaceSize);
                            break;
                        case 2:
                            pos = new Vector3(Corporation.SpaceSize, Corporation.SpaceSize / 2, Corporation.SpaceSize);
                            break;
                        case 3:
                            pos = new Vector3(-Corporation.SpaceSize, Corporation.SpaceSize / 2, Corporation.SpaceSize);
                            break;
                    }

                    _Exits.Add(new SectorExit(exitName, pos));                    
                    e++;
                }
            }
        }

        [NonSerialized]
        public GeomInstancer CorpInstancer;

        public CyberSector(Game1 game, string name, Corporation playerCorp)
        {
            Game = game;
            Name = name;
            playerCorp.SectorBase = Name;
            Corporations.Add(playerCorp);
            CreateCorporations();            
        }
        public CyberSector(Game1 game, string name)
        {
            Game = game;
            Name = name;
            CreateCorporations();
        }

        public void GotoExit(string name)
        {
            SectorExit exit = _Exits.SingleOrDefault(entity => entity.Name == name);

            if (exit != null)
            {
                Game.camera.Position = exit.Position;
                Game.camera.Rotation = Game1.LookAtLockRotation(Vector3.Zero, 1, Game.camera.Position, Game.camera.Rotation, Vector3.Forward, Vector3.Forward);
            }
        }

        public void EndCycle(string cycleDate)
        {
            // Do cycle finances
            foreach (Corporation corp in Corporations)
                corp.EndCycle(cycleDate);

            // Reset world stuff
            RenderStatic = false;
            speedTran = speedTranBase;
        }

        public void UpdateCycle(GameTime gameTime)
        {
            foreach (Corporation corp in Corporations)
            {
                bool stockUp = rnd.Next(2) == 1;
                decimal stockMvmt = (decimal)MathHelper.Lerp(0,.1f,(float)rnd.NextDouble()) * (stockUp ? 1 : -1);
                corp.SharePrice += stockMvmt;
            }            
            
        }

        List<decimal> tst = new List<decimal>();

        public void CreateCorporations()
        {
            // Create corperate landscape...
            for (int x = 0; x < 255; x++)
            {
                //string.Format("Corp {0:00}", Corporation.CorporationCount)
                Corporations.Add(new Corporation(Game,NameFactory.CreateCorporationName(), MathHelper.Lerp(1, 8, (float)rnd.NextDouble())) { Description = "...", SectorBase = Name });
                // Does the new corpcontat any of the others?
                for (int col = 0; col < Corporations.Count - 1; col++)
                {
                    if (Corporations[Corporations.Count - 1] != Corporations[col] && Corporations[Corporations.Count - 1].Bounds.Intersects(Corporations[col].Bounds))
                    {
                        Corporations[Corporations.Count - 1].Position = Corporations[Corporations.Count - 1].genNewPosition(Corporation.SpaceSize);
                        col = -1;
                    }
                }
            }
        }

        public void LeaveCorp()
        {
            Game.camera.Position = inSideCorp.name3DPos;
            Game.camera.Rotation = Game1.LookAtLockRotation(Game.camLastPos, 1, Game.camera.Position, Game.camera.Rotation, Vector3.Forward, Vector3.Forward);
            Game.camera.Translate(Vector3.Forward * 1.5f);
            inSideCorp.ExitCorp();
            inSideCorp = null;
        }

        public void EnterCorp(Corporation corp)
        {
            inSideCorp = corp;
            inSideCorp.EnterCorp();

            Game.camLastPos = Game.camera.Position;
            Game.camera.Position = Vector3.Backward * 20;
            Game.camera.Rotation = Quaternion.Identity;

            string cpName = corp.Name.Replace(" Co.", ", The Company").Replace(" Bros.", " Brothers").Replace(" Sis.", " Sisters").Replace(" Inc.", ", Incorporated").Replace(" Asc.", " Associates").Replace(" Ascn.", " Association").Replace(", ", "; ");
            
            if(corp == Game.playerCorp)
                Game.Say(string.Format("Welcome to {0}, your home", cpName));
            else
                Game.Say(string.Format("Welcome to {0}", cpName));
        }

        

        public void Update(GameTime gameTime)
        {
            if (Keyboard.GetState().IsKeyDown(Keys.W))
                Game.camera.Translate(Vector3.Forward * speedTran);
            if (Keyboard.GetState().IsKeyDown(Keys.S))
                Game.camera.Translate(Vector3.Backward * speedTran);
            if (Keyboard.GetState().IsKeyDown(Keys.A))
                Game.camera.Translate(Vector3.Left * speedTran);
            if (Keyboard.GetState().IsKeyDown(Keys.D))
                Game.camera.Translate(Vector3.Right * speedTran);

            if (Keyboard.GetState().IsKeyDown(Keys.Left))
                Game.camera.Rotate(Vector3.Up, speedRot);
            if (Keyboard.GetState().IsKeyDown(Keys.Right))
                Game.camera.Rotate(Vector3.Up, -speedRot);
            if (Keyboard.GetState().IsKeyDown(Keys.Up))
                Game.camera.Rotate(Vector3.Right, speedRot);
            if (Keyboard.GetState().IsKeyDown(Keys.Down))
                Game.camera.Rotate(Vector3.Right, -speedRot);

            if (inSideCorp == null && Keyboard.GetState().IsKeyDown(Keys.Space))
                Game.camera.Rotation = Game1.LookAtLockRotation(Game.playerCorp.Position, 1, Game.camera.Position, Game.camera.Rotation, Vector3.Forward, Vector3.Forward);

            if (CorpInstancer == null)
                SetupCorpInstancer();

            float distToCam = float.MaxValue;
            Corporation nearCorp = null;

            if (inSideCorp == null)
            {
                foreach (Corporation c in Corporations)
                {
                    c.Update(gameTime);
                    if (Game.IsMouseOverCorporation(c))
                    {
                        float d = c.distFromCamera;
                        if (d < distToCam)
                        {
                            distToCam = d;
                            nearCorp = c;
                        }                        
                    }
                }

                if (nearCorp != null && Game.IsMouseOverCorporation(nearCorp) && Game.LeftButtonPressed)
                    EnterCorp(nearCorp);

                if (nearCorp != hoverCorp)
                {
                    if (nearCorp != null)
                    {
                        if (hoverCorp != null)
                            hoverCorp.OuterColor = Color.Lime;

                        hoverCorp = nearCorp;
                        if (hoverCorp.OuterColor != Color.Red && Game.AudioOn && Game.SFXOn)
                            Game.Content.Load<SoundEffect>("Audio/SFX/Hover").Play(.1f, 0, 0);

                        hoverCorp.OuterColor = Color.Red;
                    }
                    else
                    {
                        hoverCorp.OuterColor = Color.Lime;
                        hoverCorp = nearCorp;
                    }
                }
                else
                {
                    if (Game.IsMouseOverUIZone != null && hoverCorp != null)
                        hoverCorp.OuterColor = Color.Lime;
                }

                foreach (SectorExit exit in _Exits)
                {
                    if (Game.IsMouseoverBox(exit.Bounds) && Game.LeftButtonPressed)
                    {
                        if (!Game.camera.Bounds.Intersects(exit.Bounds))
                        {
                            Game.SetCurrentSector(exit.Name);
                            break;
                        }
                    }
                }
            }
            else
            {
                inSideCorp.Update(gameTime);

                if (Keyboard.GetState().IsKeyDown(Keys.Escape))
                    LeaveCorp();
            }

            CorpInstancer.Update(gameTime);
        }

        public void Draw(GameTime gameTime)
        {
            DrawWalls(gameTime);
            DrawCorps(gameTime);
            DrawFloor(gameTime);
            
        }

        protected void SetupCorpInstancer()
        {
            CorpInstancer = new GeomInstancer(Game, "Models/Block");
            CorpInstancer.OrderByDistanceFromCamera = true;
            CorpInstancer.Initialize();
        }
        
        List<Corporation> renderCorps;
        public void DrawCorps(GameTime gameTime)
        {
            //GraphicsDevice.DepthStencilState = DepthStencilState.None;
            Game.GraphicsDevice.BlendState = BlendState.AlphaBlend;

            if (CorpInstancer == null)
                SetupCorpInstancer();

            if (inSideCorp == null)
            {
                
                renderCorps = Corporations.OrderByDescending(entity => entity.distFromCamera).ToList();

                // re order the instance list.

                // Draw sector exits
                foreach (SectorExit exit in _Exits)
                    exit.Draw(Game, gameTime);

                CorpInstancer.Draw(gameTime, "OutsideRenderInstanced");

                foreach (Corporation corp in renderCorps)
                {
                    //if (Game.camera.Frustum.Intersects(corp.Bounds)) // It's quite expensive to do this!..
                    {
                        corp.Draw(gameTime);

                        if (corp.OuterColor == Color.Red || corp == Game.playerCorp)
                            corp.DrawCorpBoxName();
                    }
                }
            }
            else
            {
                inSideCorp.DrawExternalNodes(gameTime);
            }
        }

        public void DrawFloor(GameTime gameTime)
        {
            Color col = Color.DarkGray;

            if (inSideCorp == null)
                Game.DrawMesh(Game.Content.Load<Model>("Models/panel"), (Matrix.CreateScale(51f, 51f, 1) * Matrix.CreateRotationX(MathHelper.PiOver2)), "DoubleSide", col, .5f);

            if (RenderStatic)
            {
                SpriteBatch spriteBatch = (SpriteBatch)Game.Services.GetService(typeof(SpriteBatch));

                string stat = string.Format("Textures/ScreenEffect/static{0}", rnd.Next(1, 10));
                spriteBatch.Draw(Game.Content.Load<Texture2D>(stat), new Rectangle(0, 0, Game.GraphicsDevice.Viewport.Width, Game.GraphicsDevice.Viewport.Height), staticColor);
                
            }
        }

        public void DrawWalls(GameTime gameTime)
        {
            // Draw the floor..
            Game.GraphicsDevice.DepthStencilState = DepthStencilState.Default;
            //GraphicsDevice.BlendState = BlendState.Opaque;
            Color col;
            if (inSideCorp == null)
                col = Color.Purple;
            else
                col = Color.Silver;

            Game.DrawMesh(Game.Content.Load<Model>("Models/Block"), (Matrix.CreateScale(Vector3.One * 10000) * Matrix.CreateTranslation(Game.camera.Position)), "InsideRender", col);

        }

        public void ReWire(Game1 game)
        {
            foreach (Corporation corp in Corporations)
                corp.ReWire(game);
        }

        public void UnWire()
        {
            foreach (Corporation corp in Corporations)
                corp.UnWire();
        }
    }
}
